/**
 * VSCode扩展API模块
 * @module vscode
 */
import * as vscode from "vscode";

/**
 * JSDoc注释解析器
 * @module comment-parser
 */
import { parse } from "comment-parser";

/**
 * Node.js子进程执行模块
 * @module child_process
 */
import { exec } from "child_process";

/**
 * Node.js文件系统模块
 * @module fs
 */
import * as fs from "fs";

/**
 * Node.js路径处理模块
 * @module path
 */
import * as path from "path";

/**
 * Node.js操作系统模块
 * @module os
 */
import * as os from "os";

/**
 * VSCode代码运行扩展主类
 * 
 * 该类负责注册和执行代码运行命令，通过解析JSDoc注释来收集函数参数，
 * 并执行选中的JavaScript函数代码。
 * 
 * @class CodeRunnerExtension
 * @example
 * ```typescript
 * const extension = new CodeRunnerExtension(context);
 * ```
 */
export class CodeRunnerExtension {
  /**
   * VSCode扩展上下文对象
   * @private
   * @type {vscode.ExtensionContext}
   */
  private context: vscode.ExtensionContext;

  /**
   * 构造函数
   * 
   * @param {vscode.ExtensionContext} context - VSCode扩展上下文
   * @description 初始化扩展并注册命令
   */
  constructor(context: vscode.ExtensionContext) {
    this.context = context;
    this.registerCommand();
  }

  /**
   * 注册VSCode命令
   * 
   * @private
   * @description 注册"extension.runSelectedCode"命令，用于执行选中的代码
   * @returns {void}
   */
  private registerCommand(): void {
    const disposable = vscode.commands.registerCommand(
      "extension.runSelectedCode",
      async () => {
        try {
          const editor = vscode.window.activeTextEditor;
          if (!editor) {
            vscode.window.showErrorMessage("没有打开的编辑器");
            return;
          }

          const code = editor.document.getText(editor.selection);
          if (!code) {
            vscode.window.showWarningMessage("请先选中一段代码");
            return;
          }

          const functionExecutor = new FunctionExecutor(code);
          const functionName = functionExecutor.detectFunctionName();
          if (!functionName) return;

          const jsDocParser = new JsDocParser(code);
          const params = jsDocParser.getParams();
          const exampleArgs = jsDocParser.getExampleArgs();

          const inputCollector = new InputCollector(params, exampleArgs);
          const args = await inputCollector.collectArgs();
          if (!args) return;

          functionExecutor.execute(functionName, args);
        } catch (err: any) {
          vscode.window.showErrorMessage(`执行失败: ${err.message}`);
        }
      }
    );

    this.context.subscriptions.push(disposable);
  }
}

/**
 * JSDoc注释解析器类
 * 
 * 该类负责解析JavaScript代码中的JSDoc注释，提取函数参数信息和示例参数。
 * 使用comment-parser库来解析JSDoc格式的注释。
 * 
 * @class JsDocParser
 * @example
 * ```typescript
 * const parser = new JsDocParser(code);
 * const params = parser.getParams();
 * const examples = parser.getExampleArgs();
 * ```
 */
class JsDocParser {
  /**
   * 要解析的JavaScript代码字符串
   * @private
   * @type {string}
   */
  private code: string;

  /**
   * 解析后的JSDoc对象
   * @private
   * @type {any | null}
   */
  private jsdoc: any | null;

  /**
   * 构造函数
   * 
   * @param {string} code - 包含JSDoc注释的JavaScript代码
   * @description 初始化解析器并解析代码中的JSDoc注释
   */
  constructor(code: string) {
    this.code = code;
    const parsed = parse(code);
    this.jsdoc = parsed.length > 0 ? parsed[0] : null;
  }

  /**
   * 获取函数参数列表
   * 
   * @returns {Array} 参数标签数组，包含参数名称、类型和描述信息
   * @description 从JSDoc注释中提取所有@param标签
   * @example
   * ```typescript
   * const params = parser.getParams();
   * // 返回: [{ tag: 'param', name: 'x', type: 'number', description: 'x坐标' }]
   * ```
   */
  getParams(): Array<{ tag: string; name: string; type: string; description: string }> {
    return this.jsdoc
      ? this.jsdoc.tags.filter((tag: { tag: string; }) => tag.tag === "param")
      : [];
  }

  /**
   * 获取示例参数值
   * 
   * @returns {any[]} 示例参数数组
   * @description 从JSDoc注释的@example标签中提取函数调用参数
   * @example
   * ```typescript
   * const examples = parser.getExampleArgs();
   * // 返回: [1, 2, "hello"] 或 []
   * ```
   */
  getExampleArgs(): any[] {
    let exampleArgs: any[] = [];
    const exampleTag = this.jsdoc?.tags.find((tag: { tag: string; }) => tag.tag === "example");
    if (exampleTag && exampleTag.source) {
      const exampleCode = exampleTag.source.map((line: { source: any; }) => line.source).join("\n");
      const match = exampleCode.match(/\((.*)\)/); // 括号里的内容
      if (match && match[1]) {
        try {
          exampleArgs = Function(`return [${match[1]}]`)();
        } catch {
          exampleArgs = [];
        }
      }
    }
    return exampleArgs;
  }
}

/**
 * 用户输入参数收集器类
 * 
 * 该类负责收集用户输入的函数参数，通过VSCode的输入框界面与用户交互，
 * 并根据JSDoc注释中的参数类型进行类型转换。
 * 
 * @class InputCollector
 * @example
 * ```typescript
 * const collector = new InputCollector(params, exampleArgs);
 * const args = await collector.collectArgs();
 * ```
 */
class InputCollector {
  /**
   * 函数参数信息数组
   * @private
   * @type {any[]}
   */
  private params: any[];

  /**
   * 示例参数值数组
   * @private
   * @type {any[]}
   */
  private exampleArgs: any[];

  /**
   * 构造函数
   * 
   * @param {any[]} params - 从JSDoc解析得到的参数信息数组
   * @param {any[]} exampleArgs - 示例参数值数组
   * @description 初始化参数收集器
   */
  constructor(params: any[], exampleArgs: any[]) {
    this.params = params;
    this.exampleArgs = exampleArgs;
  }

  /**
   * 收集用户输入的参数
   * 
   * @async
   * @returns {Promise<any[] | null>} 用户输入的参数数组，如果用户取消则返回null
   * @description 通过VSCode输入框逐个收集用户输入的参数值，并进行类型转换
   * @example
   * ```typescript
   * const args = await collector.collectArgs();
   * if (args) {
   *   // 用户输入了所有参数
   *   console.log('参数:', args);
   * } else {
   *   // 用户取消了输入
   *   console.log('用户取消了操作');
   * }
   * ```
   */
  async collectArgs(): Promise<any[] | null> {
    const args: any[] = [];
    for (let i = 0; i < this.params.length; i++) {
      const param = this.params[i];
      const defaultVal =
        this.exampleArgs[i] !== undefined
          ? JSON.stringify(this.exampleArgs[i])
          : undefined;

      const input = await vscode.window.showInputBox({
        prompt: `请输入参数: ${param.name} (${param.type})`,
        placeHolder: param.description || "",
        value: defaultVal,
      });

      if (input === undefined) return null; // 用户取消

      try {
        args.push(this.convertType(input, param.type));
      } catch (err: any) {
        vscode.window.showErrorMessage(
          `参数 ${param.name} 转换失败: ${err}`
        );
        return null;
      }
    }
    return args;
  }

  /**
   * 将用户输入的字符串转换为指定类型
   * 
   * @private
   * @param {string} input - 用户输入的字符串
   * @param {string | undefined} type - 目标类型
   * @returns {any} 转换后的值
   * @throws {Error} 当类型转换失败时抛出错误
   * @description 根据JSDoc注释中的类型信息，将字符串输入转换为相应的数据类型
   * @example
   * ```typescript
   * const num = this.convertType("123", "number"); // 返回 123
   * const bool = this.convertType("true", "boolean"); // 返回 true
   * const obj = this.convertType('{"a": 1}', "object"); // 返回 {a: 1}
   * ```
   */
  private convertType(input: string, type: string | undefined): any {
    const paramType = type?.toLowerCase() || "";

    if (paramType.includes("array") || paramType.includes("[]") || paramType.includes("object")) {
      return JSON.parse(input.replace(/\\"/g, '"'));
    } else if (paramType.includes("number")) {
      const num = Number(input);
      if (isNaN(num)) throw new Error("不是有效的数字");
      return num;
    } else if (paramType.includes("boolean")) {
      return input.toLowerCase() === "true";
    } else {
      return input;
    }
  }
}

/**
 * 函数执行器类
 * 
 * 该类负责检测JavaScript代码中的函数定义，并将函数代码写入临时文件执行。
 * 支持普通函数和箭头函数的检测，通过Node.js子进程执行代码并返回结果。
 * 
 * @class FunctionExecutor
 * @example
 * ```typescript
 * const executor = new FunctionExecutor(code);
 * const functionName = executor.detectFunctionName();
 * if (functionName) {
 *   executor.execute(functionName, args);
 * }
 * ```
 */
class FunctionExecutor {
  /**
   * 处理后的JavaScript代码字符串
   * @private
   * @type {string}
   */
  private code: string;

  /**
   * 构造函数
   * 
   * @param {string} code - 包含函数定义的JavaScript代码
   * @description 初始化执行器并移除export关键字，使代码可以在临时文件中直接执行
   */
  constructor(code: string) {
    // 移除 export 关键字，使其可以在临时文件中直接执行
    this.code = code.replace(/export\s+/g, '');
  }

  /**
   * 检测代码中的函数名称
   * 
   * @returns {string | null} 检测到的函数名称，如果未找到则返回null
   * @description 使用正则表达式检测普通函数和箭头函数的定义
   * @example
   * ```typescript
   * const functionName = executor.detectFunctionName();
   * if (functionName) {
   *   console.log('找到函数:', functionName);
   * } else {
   *   console.log('未找到函数定义');
   * }
   * ```
   */
  detectFunctionName(): string | null {
    const functionRegex = /function\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*\([^)]*\)\s*\{/g;
    const match = functionRegex.exec(this.code);
    if (match) return match[1];

    const arrowRegex = /const\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*=\s*\([^)]*\)\s*=>/g;
    const arrowMatch = arrowRegex.exec(this.code);
    if (arrowMatch) return arrowMatch[1];

    vscode.window.showErrorMessage("未找到函数定义");
    return null;
  }

  /**
   * 执行函数并显示结果
   * 
   * @param {string} functionName - 要执行的函数名称
   * @param {any[]} args - 函数参数数组
   * @returns {void}
   * @description 将函数代码和调用语句写入临时文件，通过Node.js执行并显示结果
   * @example
   * ```typescript
   * executor.execute("add", [1, 2]);
   * // 将执行: console.log(add(1, 2))
   * ```
   */
  execute(functionName: string, args: any[]): void {
    const tempDir = os.tmpdir();
    const tempFile = path.join(tempDir, `temp_func_${Date.now()}.js`);

    let funcArgs = args.length === 1 && Array.isArray(args[0])
      ? JSON.stringify(args[0])
      : args.map(a => JSON.stringify(a)).join(",");

    const fullCode = `${this.code}\nconsole.log(${functionName}(${funcArgs}))`;

    try {
      fs.writeFileSync(tempFile, fullCode);
      exec(`node "${tempFile}"`, (error, stdout, stderr) => {
        try { fs.unlinkSync(tempFile); } catch { }
        if (error) return vscode.window.showErrorMessage(`执行出错: ${error}`);
        if (stderr) return vscode.window.showErrorMessage(`错误: ${stderr}`);
        vscode.window.showInformationMessage(`输出: ${stdout.trim()}`);
      });
    } catch (err: any) {
      vscode.window.showErrorMessage(`写入临时文件失败: ${err.message}`);
    }
  }
}

/**
 * VSCode扩展激活函数
 * 
 * 当VSCode扩展被激活时调用此函数，初始化代码运行扩展。
 * 
 * @param {vscode.ExtensionContext} context - VSCode扩展上下文对象
 * @returns {void}
 * @description 创建CodeRunnerExtension实例并注册相关命令
 * @example
 * ```typescript
 * // 在package.json中配置activationEvents
 * "activationEvents": ["onCommand:extension.runSelectedCode"]
 * ```
 */
export function activate(context: vscode.ExtensionContext): void {
  new CodeRunnerExtension(context);
}

/**
 * VSCode扩展停用函数
 * 
 * 当VSCode扩展被停用时调用此函数，执行清理操作。
 * 
 * @returns {void}
 * @description 目前无需特殊清理操作，保留此函数以备将来扩展
 */
export function deactivate(): void { }

